package dislock

import (
	"context"
	"fmt"
	"github.com/go-redis/redis/v8"
	"github.com/satori/go.uuid"
	"log"
	"sync"
	"time"
)

var counter int64
var wg sync.WaitGroup

//分布式key
var lockKey = "dislock"

//分布式锁场景
func lock(rdb *redis.Client, myfunc func()) {
	ctx := context.Background()
	defer wg.Done()
	//获取value值
	uuid := getUuid()
	//加锁
	res, err := rdb.SetNX(ctx, lockKey, uuid, time.Second*5).Result()
	if err != nil {
		log.Printf("%+v", err)
		return
	}
	if !res {
		fmt.Println("append lock fail")
		return
	} else {
		fmt.Println("append lock")
	}
	//需要加锁的任务
	myfunc()
	//解锁，先判断value是否相等来确认是否是当前协程
	//采用lua来保证原子操作
	var luaScript = redis.NewScript(`
		if redis.call("get", KEYS[1]) == ARGV[1]
			then
				return redis.call("del", KEYS[1])
			else
				return 0
		end
	`)
	rs, err := luaScript.Run(ctx, rdb, []string{lockKey}, uuid).Result()
	if err != nil {
		log.Printf("%+v", err)
		return
	}
	if rs == 0 {
		fmt.Println(" release lock fail")
	} else {
		fmt.Println("release lock success")
	}
}

//获取uuid
func getUuid() string {
	out := uuid.NewV4().String()
	return out
}

//测试任务
func test() {
	counter++
	time.Sleep(1 * time.Second)
	fmt.Printf("test is %d\n", counter)
}

//执行测试
func Task(rdb *redis.Client) {
	for i := 0; i < 10; i++ {
		wg.Add(1)
		go func() {
			lock(rdb, test)
		}()
	}
	wg.Wait()
	fmt.Printf("the last counter is %d\n", counter)
}
